
目前，我们只讨论了提前(AOT)编译器，这些编译器编译整个应用程序。应用程序只能在编译完成后运行，若编译是在应用程序的运行时执行的，编译器就是JIT编译器。JIT编译器有一些有趣的用例:

\begin{itemize}
\item
实现虚拟机:编程语言可以用AOT编译器翻译成字节码。运行时，使用JIT编译器将字节码编译为机器码。这种方法的优点是字节码与硬件无关，并且由于JIT编译器，与AOT编译器相比没有性能损失。Java和C\#现在使用这个模型，但这并不是一个新想法:1977年的USCD Pascal编译器已经使用了类似的方法。

\item
表达式求值:电子表格应用程序可以使用JIT编译器编译经常执行的表达式。例如，这可以加快金融模拟。lldb LLVM调试器使用这种方法在调试时计算表达式。

\item
数据库查询:数据库从数据库查询创建一个执行计划。执行计划描述了对表和列的操作，执行时产生查询答案。可以使用JIT编译器将执行计划转换为机器码，从而加快查询的执行速度。
\end{itemize}

LLVM的静态编译模型与JIT模型的距离并不像人们想象的那么遥远，LLVM静态编译器将LLVM IR编译成机器码，并将结果保存为磁盘上的目标文件。若目标文件不是存储在磁盘上，而是存储在内存中，代码是可执行的吗?不是直接的，对全局函数和全局数据的引用使用重定位而不是绝对地址。从概念上讲，重定位描述了如何计算地址——例如，作为已知地址的偏移量。若像链接器和动态加载器将重定位解析为地址，就可以执行目标代码了。运行静态编译器将IR代码编译成内存中的对象文件，在内存中的对象文件上执行链接步骤，然后运行代码，就得到了一个JIT编译器。

LLVM核心库中的JIT实现就是基于这个思想。LLVM的开发历史中，有几个JIT实现，具有不同的功能集。最新的JIT API是按请求编译(ORC)引擎。若对这个缩略词感到好奇，在可执行和链接格式(ELF)和调试标准(DWARF)出现之后，首席开发人员打算根据托尔金的世界创造另一个缩略词。

ORC引擎基于并扩展了在内存中，对象文件上使用静态编译器和动态链接器的思想。实现使用分层的方法。两个基本层次是编译层和链接层，在此之上有一层提供延迟编译支持。转换层可以堆叠在惰性编译层之上或之下，允许开发人员添加转换或简单地收到某些事件的通知。此外，这种分层的方法还有一个优点，即JIT引擎可以针对不同的需求进行定制。例如，高性能的虚拟机可能选择提前编译所有内容，而不使用延迟编译层。另一方面，其他虚拟机将强调启动时间和对用户的响应，并将在惰性编译层的帮助下实现这一点。

旧的MCJIT引擎仍然可用，其API来自一个更旧的、已经删除的JIT引擎。随着时间的推移，这个API逐渐变得臃肿，缺乏ORC API的灵活性。

我们的目标是删除这个实现，因为ORC引擎现在提供了MCJIT引擎的所有功能，新的开发应该使用ORC API。下一节中，深入实现JIT编译器之前，我们将研究LLVM解释器和动态编译器。








































